home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
076-100
/
disk_095
/
cmd
/
cmd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-06
|
17KB
|
625 lines
/* Cmd.c --- v4 --- Carolyn Scheppner CBM 07/87
*
* Copyright (c) 1987 Commodore Business Machines - All Rights Reserved
* This code may be freely non-commercially redistributed.
*
* Redirects exec serial or parallel device CMD_WRITEs to a file
* (for the purpose of capturing printer output in a file)
* Built upon fragments of Read (author?) and NoFastMem (Andy Finkel)
*
* CLI Usage: [run] cmd [-s] [-m] [-n] devicename filename
* -s (Skip) skips any short initial write (usually a Reset if screendump)
* -m (Multiple) causes cmd to remain installed for multiple files
* -n (Notify) enables helpful progress messages
* devicename serial or parallel
*
* WB Usage: Just doubleclick.
* Specify the args in your icon's ToolTypes (use WB Info)
* Built-in defaults are:
* DEVICE=parallel
* FILE=ram:CMD_file
* SKIP=FALSE
* MULTIPLE=FALSE
* NOTIFY=FALSE
*
* Note: On a screen dump, first CMD_WRITE is usually a printer RESET.
* The printer device then delays long enough for the reset
* to complete, to prevent the loss of subsequent output data.
* When the dump is instead captured in a file, this delay
* is of course lost. If your printer driver outputs a reset
* at the start of a dump (as ours do), use the -s (SKIP) option
* to keep the initial CMD_WRITE out of the file.
*
* Sorry about the busywait synchronization of the device wedge
* and the main process. The purpose was to avoid unnecessary
* meddling with the message structures and the device's signals.
* I had to add a conditional kludge in MyBeginIO to allow Cmd
* to work with our HPLaser drivers which do PWrites within a Forbid
* in their Close logic to print/eject last sheet, and also apparently
* during their open logic if drivers are resident.
*
* v2 mods: changes to MyBeginIO for -1 and 0 length CMD_WRITES, usage
* v3 mods: added buffering of small writes to speed file IO
* v4 mods: Conditional kludges added to MyBeginIO for HPLaser
* (if Forbidden, sneaks the data into main's write buffer)
* (EXTRALEN added to wbuf size to allow extra room for this)
* myWrite now doesn't Write if len = 0
* MyClose now conditional on writecnt, not reqcnt
*
* Linkage info (requires assembler module cmda):
* Compile with -v on LC2.
* FROM LIB:Astartup.obj, cmd.o, cmda.o
* TO cmd
* LIBRARY LIB:Amiga.lib,LIB:LC.lib
*/
#include "exec/types.h"
#include "exec/memory.h"
#include "exec/io.h"
#include "exec/libraries.h"
#include "exec/execbase.h"
#include "libraries/dos.h"
#include "libraries/dosextens.h"
#include "workbench/startup.h"
#include "workbench/workbench.h"
#include "devices/serial.h"
#include "devices/parallel.h"
/* #define DEBUG */
#define TOUPPER(c) ((c)>='a'&&(c)<='z'?(c)-'a'+'A':(c))
#define HIGHER(x,y) ((x)>(y)?(x):(y))
#define WBUFLEN 2048L
#define EXTRALEN 256L
#define INBUFLEN 40L
#define REQSIZE 120L /* should be big enough or any OpenDevice */
#define DEV_CLOSE LIB_CLOSE
#define DEV_EXPUNGE LIB_EXPUNGE
/* DEV_BEGINIO (-30) defined in exec/io.h */
#define OPEN_SIG SIGBREAKF_CTRL_E
#define WRITE_SIG SIGBREAKF_CTRL_F
#define CLOSE_SIG SIGBREAKF_CTRL_D
#define BREAK_SIG SIGBREAKF_CTRL_C
#define SHORT_WRITE (8L)
extern VOID myBeginIO(); /* The assembler entry */
extern VOID myClose(); /* The assembler entry */
extern VOID myExpunge(); /* The assembler routine */
extern struct ExecBase *SysBase;
extern struct MsgPort *CreatePort();
extern struct WBStartup *WBenchMsg;
ULONG RealBeginIO, NewBeginIO;
ULONG RealClose, NewClose;
ULONG RealExpunge, NewExpunge;
char *noMem = "Out of memory\n";
char *portName = "cas_TMP_CMD_PORT";
char *conSpec = "CON:20/20/600/40/ CMD v4";
char u1[]={"\nCLI Usage: [run] Cmd [-s] [-m] [-n] devicename filename\n"};
char u2[]={" devicename = serial or parallel\n"};
char u3[]={" -s = SKIP any short initial write (usually a reset if screendump)\
n"};
char u4[]={" -m = installed for MULTIPLE files until Break or CTRL_C\n"};
char u5[]={" -n = enables NOTIFY (helpful progress messages)\n\n"};
char u6[]={"WB Tooltypes: DEVICE, FILE, and booleans SKIP,MULTIPLE,NOTIFY\n"};
char u7[]={" Cancel installation for multiple files by reclicking\n\n"};
char *us[7] = {u1,u2,u3,u4,u5,u6,u7};
char *morehelp = "Type cmd ? for more help\n\n";
char *prevTaskName = NULL;
char *outFileName, *deviceName;
char mainTaskName[40];
char wbDev[INBUFLEN], wbFile[INBUFLEN];
char sbuf[120], *wbuf = 0;
struct Device *TheDevice;
struct Task *otherTask, *mainTask;
struct IOStdReq *myReq, *ioR;
struct MsgPort *port;
LONG wLen = 1, outFile = NULL;
ULONG total = 0;
ULONG IconBase = NULL;
BOOL Error1 = TRUE, Skip = FALSE, Multiple = FALSE, Notify = FALSE;
BOOL Done = FALSE, FromWb = FALSE, MainBusy = FALSE;
int reqcnt = 0, writecnt = 0, filecnt = 0; fnLen, wi;
char cprt[] =
"Copyright (c) 1987 Commodore Business Machines All Rights Reserved";
VOID MyBeginIO(ior)
struct IOStdReq *ior;
{
BOOL Forbidden;
char *data;
int k;
/* The code conditional on Forbidden is needed to work with
* HPLaser drivers which PWrite during a Forbid in their Close
* logic to print and eject last sheet, and also apparently
* during the initial write if drivers are resident.
*/
Forbidden = (SysBase->TDNestCnt >= 0) ? TRUE : FALSE;
reqcnt += 1;
if((ior->io_Command == CMD_WRITE)&&(ior->io_Length))
{
writecnt += 1;
if(writecnt==1)
{
if(!Forbidden) while(MainBusy);
MainBusy = TRUE;
Signal(mainTask,OPEN_SIG);
if(!Forbidden) while(MainBusy);
}
/* If device CMD_WRITE uses length -1, convert to actual length */
if(ior->io_Length==-1) ior->io_Length = strlen(ior->io_Data);
if((!Skip)||(writecnt>1)||(ior->io_Length > SHORT_WRITE))
{
/* This conditional kludge needed to work with HPLaser
* drivers which PWrite during a Forbid in their
* Close logic to print/eject last sheet
*/
if(Forbidden)
{
if(ior->io_Length < (WBUFLEN + EXTRALEN - wi))
{
data = (char *)ior->io_Data;
for(k=0; k<ior->io_Length; k++, wi++) wbuf[wi]=data[k];
}
}
else
{
while(MainBusy);
MainBusy = TRUE;
ioR = ior;
Signal(mainTask,WRITE_SIG); /* Signal write */
while(MainBusy);
}
}
ior->io_Actual = ior->io_Length;
}
if(!(ior->io_Flags & IOF_QUICK)) ReplyMsg(ior);
}
VOID MyClose(ior)
struct IOStdReq *ior;
{
/* Note - Exec has us in a forbid here */
if(writecnt) /* Ignores DOS's initial Open/Close/Open */
{
Signal(mainTask,CLOSE_SIG); /* Signal Close */
}
}
main(argc, argv)
UWORD argc;
TEXT *argv[];
{
ULONG signals;
int k;
FromWb = (argc==0) ? TRUE : FALSE;
if(FromWb)
{
getWbArgs(WBenchMsg);
deviceName = wbDev;
outFileName = wbFile;
}
else
{
if(strEqu(argv[1], "?")) usageHelpExit();
if(argc<3) usageExit();
for(k=1; argv[k][0]=='-'; k++)
{
if(argv[k][1] == 's') Skip = TRUE;
if(argv[k][1] == 'm') Multiple = TRUE;
if(argv[k][1] == 'n') Notify = TRUE;
}
if(argc-k < 2) usageExit();
deviceName = argv[k++];
outFileName = argv[k];
}
fnLen = strlen(outFileName); /* Used if Multiple extension added */
/* Result will be mainTaskName = "cas_CMD_whatever.device"
* with deviceName pointing to the eighth character
*/
strcpy(&mainTaskName[0],"cas_CMD_");
strcpy(&mainTaskName[strlen(mainTaskName)],deviceName);
strcpy(&mainTaskName[strlen(mainTaskName)],".device");
deviceName = &mainTaskName[8];
Forbid();
if(otherTask = (struct Task *)FindTask(mainTaskName))
{
Permit();
if(FromWb) Signal(otherTask,BREAK_SIG);
else printf("Device already redirected... exiting\n");
cleanexit();
}
mainTask = (struct Task *)FindTask(NULL);
prevTaskName = mainTask->tc_Node.ln_Name;
mainTask->tc_Node.ln_Name = mainTaskName;
Permit();
/* initialize */
if(!(wbuf = (char *)AllocMem(WBUFLEN+EXTRALEN,MEMF_PUBLIC|MEMF_CLEAR)))
cleanexit("Can't allocate write buffer\n");
wi = 0; /* index into wbuf */
if(!(port = CreatePort(portName, 0))) cleanexit("Can't open port\n");
myReq = (struct IOStdReq *)AllocMem(REQSIZE,MEMF_CLEAR|MEMF_PUBLIC);
if (!myReq) cleanexit(noMem);
myReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
myReq->io_Message.mn_ReplyPort = port;
if(OpenDevice(deviceName, 0, myReq, 0))
{
sprintf(sbuf,"Can't open %s\n",deviceName);
cleanexit(sbuf);
}
TheDevice = myReq->io_Device;
/* Install device IO redirection */
Forbid();
RealBeginIO = SetFunction(TheDevice, DEV_BEGINIO, myBeginIO);
RealClose = SetFunction(TheDevice, DEV_CLOSE, myClose);
RealExpunge = SetFunction(TheDevice, DEV_EXPUNGE, myExpunge);
Permit();
/* Expunge disabled, CloseDevice so another can open it */
CloseDevice(myReq);
if(Notify)
{
sprintf(sbuf,"Cmd redirection of %s installed\n",deviceName);
message(sbuf);
}
while(!Done)
{
signals = Wait(OPEN_SIG|WRITE_SIG|CLOSE_SIG|BREAK_SIG);
if(signals & OPEN_SIG) /* Open */
{
if(!outFile) /* No output file currently open */
{
if(Multiple) /* If Multiple, add .n extension to filename */
{
filecnt++;
sprintf(&outFileName[fnLen],".%ld",filecnt);
}
/* open output file */
outFile = Open(outFileName, MODE_NEWFILE);
wLen = 1;
total = 0;
/* This moved due to sneak-into-buffer HP kludge */
/* wi = 0; Init now at Alloc, and each Close */
Error1 = TRUE;
if(Notify)
{
sprintf(sbuf,"Redirecting %s to %s\n",
deviceName,outFileName);
message(sbuf);
}
}
#ifdef DEBUG
printf("Processed OPEN_SIG, file %s, handle $%lx\n",
outFileName,outFile);
#endif
}
if(signals & WRITE_SIG) /* Write */
{
if((outFile)&&(wLen > -1))
{
wLen = bufOrWrite(outFile,ioR->io_Data,ioR->io_Length);
}
else if(Error1)
{
message("Cmd file error: Cancel device output\n");
Error1 = FALSE;
}
#ifdef DEBUG
printf("Processed WRITE_SIG, ioLen %ld, wLen %ld, Error1 = %ld\n",
ioR->io_Length, wLen, Error1);
#endif
}
if(signals & (CLOSE_SIG|BREAK_SIG))
{
/* Close file now so user can copy even if something is wrong */
/* Null the handle - to prevent Write or re-Close */
if(!Multiple) signals |= BREAK_SIG;
if(outFile)
{
/* Write buffer contents */
if((wi>0)&&(wLen>-1)) wLen = myWrite(outFile,wbuf,wi);
wi = 0; /* moved from Open logic */
Forbid();
Close(outFile);
outFile = NULL;
writecnt = 0;
reqcnt = 0;
Permit();
if((!Multiple)||(Notify))
{
sprintf(sbuf,"Redirected %ld bytes from %s to %s\n",
total,deviceName,outFileName);
message(sbuf);
}
}
#ifdef DEBUG
printf("Processed CLOSE_SIG, total %ld\n", total);
#endif
}
if(signals & BREAK_SIG)
{
#ifdef DEBUG
printf("Got BREAK_SIG\n");
#endif
while(!Done)
{
/* Wait till we can reopen the device */
while(OpenDevice(deviceName, 0L, myReq, 0L)) Delay(50L);
/* If it's been re-loaded, we can leave */
/* Shouldn't be possible since we disabled Expunge */
if((ULONG)myReq->io_Device != (ULONG)TheDevice)
{
Done = TRUE;
}
else
{
Forbid();
NewBeginIO = SetFunction(TheDevice, DEV_BEGINIO, RealBeginIO);
NewClose = SetFunction(TheDevice, DEV_CLOSE, RealClose);
NewExpunge = SetFunction(TheDevice, DEV_EXPUNGE, RealExpunge);
if((NewBeginIO != (ULONG)myBeginIO)
||(NewClose != (ULONG)myClose)
||(NewExpunge != (ULONG)myExpunge))
{
/* Someone else has changed the vectors */
/* We put theirs back - can't exit yet */
SetFunction(TheDevice, DEV_BEGINIO, NewBeginIO);
SetFunction(TheDevice, DEV_CLOSE , NewClose);
SetFunction(TheDevice, DEV_CLOSE, NewClose);
SetFunction(TheDevice, DEV_CLOSE , NewClose);
SetFunction(TheDevice, DEV_EXPUNGE, NewExpunge);
}
else
{
Done = TRUE;
}
Permit();
}
CloseDevice(myReq);
if(!Done) message("Vectors have changed - can't restore\n");
}
}
MainBusy = FALSE;
}
sprintf(sbuf,"\nCmd redirection of %s removed\n", deviceName);
cleanexit(sbuf);
}
/* Output buffering */
bufOrWrite(fh,data,len)
LONG fh;
char *data;
int len;
{
int k, wlen;
wlen = len;
/* If possible, just buffer the output data */
if(len < WBUFLEN - wi)
{
for(k=0; k<len; k++, wi++) wbuf[wi] = data[k];
}
else
{
/* Else output any buffered data to the file */
if(wi>0) wlen = myWrite(fh,wbuf,wi);
wi = 0;
/* Then either buffer or write out current request */
if(wlen > -1)
{
if(len < WBUFLEN)
{
for(k=0; k<len; k++, wi++) wbuf[wi] = data[k];
wlen = len;
}
else
{
wlen = myWrite(fh,data,len);
}
}
}
return(wlen);
}
/* myWrite also updates total */
myWrite(fh,data,len)
LONG fh;
char *data;
int len;
{
int wlen = 0;
if(len)
{
wlen = Write(fh,data,len);
if (wlen > -1) total += wlen;
}
return(wlen);
}
/* Cleanup and exits */
usageHelpExit()
{
int k;
for(k=0; k<7; k++) printf(us[k]);
exit(RETURN_OK);
}
usageExit()
{
printf(u1);
printf(morehelp);
exit(RETURN_OK);
}
cleanexit(s)
char *s;
{
message(s);
cleanup();
exit(RETURN_OK);
}
cleanup()
{
if(myReq) FreeMem(myReq,REQSIZE);
if(port) DeletePort(port);
if(outFile) Close(outFile);
if(wbuf) FreeMem(wbuf,WBUFLEN+EXTRALEN);
Forbid();
if(prevTaskName) mainTask->tc_Node.ln_Name = prevTaskName;
Permit();
}
message(s)
char *s;
{
LONG con;
if((!FromWb)&&(*s)) printf(s);
if((FromWb)&&(*s)&&(con = Open(conSpec,MODE_OLDFILE)))
{
Write(con,s,strlen(s));
Delay(120L);
Close(con);
}
}
getWbArgs(wbMsg)
struct WBStartup *wbMsg;
{
struct WBArg *wbArg;
struct DiskObject *diskobj;
char **toolarray;
char *s;
/* Defaults */
strcpy(wbDev,"parallel");
strcpy(wbFile,"ram:CMD_file");
Skip = FALSE;
Multiple = FALSE;
Notify = FALSE;
wbArg = wbMsg->sm_ArgList;
if((IconBase = OpenLibrary("icon.library", 0)))
{
diskobj=(struct DiskObject *)GetDiskObject(wbArg->wa_Name);
if(diskobj)
{
toolarray = (char **)diskobj->do_ToolTypes;
if(s=(char *)FindToolType(toolarray,"DEVICE")) strcpy(wbDev,s);
if(s=(char *)FindToolType(toolarray,"FILE")) strcpy(wbFile,s);
if(s=(char *)FindToolType(toolarray,"SKIP"))
{
if(strEqu(s,"TRUE")) Skip = TRUE;
}
if(s=(char *)FindToolType(toolarray,"MULTIPLE"))
{
if(strEqu(s,"TRUE")) Multiple = TRUE;
}
if(s=(char *)FindToolType(toolarray,"NOTIFY"))
{
if(strEqu(s,"TRUE")) Notify = TRUE;
}
FreeDiskObject(diskobj);
}
CloseLibrary(IconBase);
}
}
/* String functions */
strEqu(p, q)
TEXT *p, *q;
{
while(TOUPPER(*p) == TOUPPER(*q))
{
if (*(p++) == 0) return(TRUE);
++q;
}
return(FALSE);
}
strlen(s)
char *s;
{
int i = 0;
while(*s++) i++;
return(i);
}
strcpy(to,from)
char *to, *from;
{
do
{
*to++ = *from;
}
while(*from++);
}
/* end */